from django.shortcuts import render, get_object_or_404, redirect, render_to_response
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import ListView
from django.db.models import Q
from django.contrib.auth.models import Group
from django.contrib.auth.decorators import login_required
from notifications.signals import notify
from django.core.cache import cache

from .models import MusicList, MusicCategory
from comment.models import MusicComment
from .forms import UploadForm
from comment.forms import MusicCommentForm
from user.models import User, LimitLike, UserFollow
from trend.models import TrendList

# Create your views here.

class musicViewIndex(ListView):
    """
    系统首页视图，呈现最新上传的12首音乐
    """

    def __init__(self):
        super(musicViewIndex).__init__()
        self.model = MusicList
        self.template_name = 'index.html'
        self.context_object_name = 'music_list'

    def get_queryset(self):
        """从缓存中读取music_list集,如果存在则直接返回给template进行渲染
        如果不存在则从数据库中读取并写入缓存之中"""
        music_list = cache.get('index_music_list')
        if not music_list:
            music_list = super(musicViewIndex, self).get_queryset().order_by('-upload_time')[:12]
            cache.set('index_music_list', music_list)
        return music_list


class musicListView(ListView):
    """
    音乐清单视图
    """

    def __init__(self):
        super(musicListView).__init__()
        self.model = MusicList
        self.template_name = 'music/music_list.html'
        self.context_object_name = 'music_list'
        self.paginate_by = 12

    def get_queryset(self):
        music_list = cache.get('music_list')
        if not music_list:
            music_list = super(musicListView, self).get_queryset().order_by('-upload_time')
            cache.set('music_list', music_list)
        return music_list

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        paginator = context.get('paginator')
        page = context.get('page_obj')
        is_paginated = context.get('is_paginated')
        pagination_data = self.pagination_data(paginator, page, is_paginated)
        context.update(pagination_data)
        return context

    def pagination_data(self, paginator, page, is_paginated):
        """
        分页
        """
        if not is_paginated:
            return {}
        left = []
        right = []
        left_has_more = False
        right_has_more = False
        first = False
        last = False
        page_number = page.number
        total_pages = paginator.num_pages
        page_range = paginator.page_range

        if page_number == 1:
            right = page_range[page_number:page_number + 4]

            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True

        elif page_number == total_pages:
            left = page_range[(page_number - 5) if (page_number - 5) > 0 else 0:page_number - 1]
            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True

        else:
            left = page_range[(page_number - 5) if (page_number - 5) > 0 else 0:page_number - 1]
            right = page_range[page_number:page_number + 2]

            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True

            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True

        data = {
            'left': left,
            'right': right,
            'left_has_more': left_has_more,
            'right_has_more': right_has_more,
            'first': first,
            'last': last,
        }

        return data


class musicCategoryView(ListView):
    """
    音乐流派视图
    """

    def __init__(self):
        super(musicCategoryView).__init__()
        self.model = MusicList
        self.template_name = 'music/music_category.html'
        self.context_object_name = 'music_list'
        self.paginate_by = 12

    def get_queryset(self):
        c_id = get_object_or_404(MusicCategory, pk=self.kwargs.get('pk'))
        music_list = cache.get('music_list_{}'.format(c_id))

        if not music_list:
            music_list = super(musicCategoryView,self).get_queryset().filter(category=c_id)
            cache.set('music_list_{}'.format(c_id), music_list)

        return music_list

    def get_context_data(self, **kwargs):
        """
        直接调用父类get_queryset方法无法传入音乐分类名称c_id,故调用此方法
        """
        context = super(musicCategoryView, self).get_context_data(**kwargs)
        c_id = get_object_or_404(MusicCategory, pk=self.kwargs.get('pk'))
        paginator = context.get('paginator')
        page = context.get('page_obj')
        is_paginated = context.get('is_paginated')
        pagination_data = self.pagination_data(paginator, page, is_paginated)

        context['c_id'] = c_id
        context.update(pagination_data)

        return context

    def pagination_data(self, paginator, page, is_paginated):
        if not is_paginated:
            return {}
        left = []
        right = []
        left_has_more = False
        right_has_more = False
        first = False
        last = False
        page_number = page.number
        total_pages = paginator.num_pages
        page_range = paginator.page_range

        if page_number == 1:
            right = page_range[page_number:page_number + 4]

            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True

        elif page_number == total_pages:
            left = page_range[(page_number - 5) if (page_number - 5) > 0 else 0:page_number - 1]
            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True

        else:
            left = page_range[(page_number - 5) if (page_number - 5) > 0 else 0:page_number - 1]
            right = page_range[page_number:page_number + 2]

            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True

            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True

        data = {
            'left': left,
            'right': right,
            'left_has_more': left_has_more,
            'right_has_more': right_has_more,
            'first': first,
            'last': last,
        }

        return data


@login_required
def music_upload(request):
    """
    音乐上传，只能在用户登录的前提下操作
    """

    # 通过ajax上传文件
    if request.method == 'POST':
        name = request.POST.get('name')
        category = request.POST.get('category')
        is_original = request.POST.get('is_original')
        is_download = request.POST.get('is_download')
        summary = request.POST.get('summary')
        music_src = request.FILES.get('music_src')
        music_cover = request.FILES.get('music_cover')

        # 检查用户是否上传过该音乐
        filter = MusicList.objects.filter(user=request.user, name=name)
        if filter:
            return JsonResponse({'status': 'warning', 'msg': '您已经上传过该音乐了!'})
        try:
            # 生成music实例，对其赋值并保存到数据库中
            music = MusicList()
            music.user = request.user
            music.name = name
            music.category_id = category
            music.is_original = is_original
            music.is_download = is_download
            music.summary = summary
            music.music_src = music_src
            music.music_cover = music_cover

            music.save()

            trend_content = '上传了音乐《{}》'.format(name)
            trend = TrendList.objects.create(user=request.user, content=trend_content)
            trend.save()

            # 通知粉丝该用户上传了新的音乐
            try:
                fans_id = list(map(lambda x: x['fan_id'], UserFollow.objects.
                                   filter(follow=request.user).values('fan_id')))
            except:
                fans_id = []
            recipient = User.objects.filter(id__in=fans_id)
            if recipient:
                notify.send(request.user, recipient=recipient,verb='{}上传了音乐《{}》'.
                            format(request.user.username,name))

        except Exception:
            return JsonResponse({'status': 'error', 'msg': '上传失败,请重试!'})

        return JsonResponse({'status': 'success', 'msg': '上传成功!'})

    music_category = MusicCategory.objects.all()

    return render(request, 'music/music_upload.html', context={'category': music_category})


def music_detail(request, pk):
    """
    音乐详情页
    """
    music = get_object_or_404(MusicList, id=pk)
    # 根据music实例中关联user的id获取MusicList中对应用户上传的所有音乐信息
    author_music_list = MusicList.objects.filter(user_id=music.user.id)[:5]
    # suggestion_list取最新上传的五首音乐
    suggestion_list = MusicList.objects.all().order_by('-upload_time')[:5]
    comment_list = MusicComment.objects.filter(music=music).order_by('collect_time')

    # 生成音乐评论表单
    form = MusicCommentForm()
    context = {'music': music,
               'author_music_list': author_music_list,
               'suggestion_list': suggestion_list,
               'comment_list' :comment_list,
               'form': form}

    return render(request, 'music/music_detail.html', context=context)


def music_search(request):
    """
    音乐搜索，根据传入的关键词Q筛选匹配的音乐并返回
    """
    q = request.GET.get('q')
    error_msg = ''

    if not q:
        error_msg = '请输入关键词'
        return render(request, 'music/music_list.html', {'error_msg': error_msg})

    music_list = MusicList.objects.filter(Q(name__contains=q))
    return render(request, 'music/music_list.html', {'error_msg': error_msg, 'music_list': music_list})


@csrf_exempt
def music_like(request):
    """
    音乐点赞，通过前端Ajax请求实现
    """
    if request.method == 'POST':
        music_id = request.POST.get('music_id', '')
        user_id = request.POST.get('user_id', '')
        user = User.objects.get(id=user_id)
        music = MusicList.objects.get(id=music_id)

        _like_count = music.like_count
        like_limit = LimitLike.objects.filter(user_id=user_id, music_id=music_id)
        if like_limit:
            return JsonResponse({'status': 'warning', 'like_count': _like_count})

        LimitLike.objects.create(user=user, music=music)
        music.like_count = _like_count + 1
        music.update()
        like_count  = music.like_count
        notify.send(user, recipient=music.user, target=music,
                    verb='{}赞了你的音乐'.format(user.username))

        trend = TrendList.objects.create(user=user, content='对音乐《{}》点赞成功'.format(music.name))
        trend.save()
        return JsonResponse({'status': 'ok', 'like_count': like_count})


def page_not_found(request):
    response = render_to_response('404.html')
    response.status_code = 404
    return response


def page_error(request):
    response = render_to_response('500.html')
    response.status_code = 500
    return response




